﻿using System;
using Microsoft.Practices.ObjectBuilder2;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace TSharp.Core.Aop.PolicyInjectionIntegrated
{
    /// <summary>
    /// 
    /// </summary>
    public class ExtendedInstanceInterceptionStrategy : InstanceInterceptionStrategy
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ExtendedInstanceInterceptionStrategy"/> class.
        /// </summary>
        /// <param name="interception">The interception.</param>
        public ExtendedInstanceInterceptionStrategy(ExtendedInterception interception)
        {
            if (null == interception)
                throw new ArgumentNullException("interception");
            Interception = interception;
        }

        /// <summary>
        /// Gets or sets the interception.
        /// </summary>
        /// <value>The interception.</value>
        public ExtendedInterception Interception { get; private set; }

        private static IInstanceInterceptionPolicy FindInterceptorPolicy(IBuilderContext context)
        {
            
            //Type buildKey = BuildKey.GetType(context.BuildKey);
            //Type type = BuildKey.GetType(context.OriginalBuildKey);
            IInstanceInterceptionPolicy policy =
                context.Policies.Get<IInstanceInterceptionPolicy>(context.BuildKey, false) ??
                context.Policies.Get<IInstanceInterceptionPolicy>(buildKey, false);
            if (policy != null)
            {
                return policy;
            }
            policy = context.Policies.Get<IInstanceInterceptionPolicy>(context.OriginalBuildKey, false) ??
                     context.Policies.Get<IInstanceInterceptionPolicy>(type, false);
            return policy;
        }

        /// <summary>
        /// Called during the chain of responsibility for a build operation. The
        /// PreBuildUp method is called when the chain is being executed in the
        /// forward direction.
        /// </summary>
        /// <param name="context">Context of the build operation.</param>
        public override void PreBuildUp(IBuilderContext context)
        {
            if (BuildKey.GetType(context.BuildKey) == typeof (IUnityContainer))
            {
                return;
            }
            IInstanceInterceptionPolicy policy = FindInterceptorPolicy(context);
            if (null != policy)
            {
                if (policy.Interceptor.CanIntercept(BuildKey.GetType(context.BuildKey)))
                {
                    Interception.SetDefaultInterceptorFor(BuildKey.GetType(context.BuildKey), policy.Interceptor);
                }
            }
            else
            {
                if (Interception.Interceptor.CanIntercept(BuildKey.GetType(context.BuildKey))
                    && Interception.Interceptor is IInstanceInterceptor)
                {
                    Interception.SetDefaultInterceptorFor(BuildKey.GetType(context.BuildKey),
                                                          (IInstanceInterceptor) Interception.Interceptor);
                }
            }
            base.PreBuildUp(context);
        }
    }
}